#include <iostream>
#include <string>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <unistd.h>
#include <cstdio>

#define ERR_EXIT(m) do{ perror(m); return; } while(0)
#define GDEFAULTNUM -1
#define GSIZE 4096

const std::string USER("user");
const std::string CREATER("creater");
const std::string pathname = ".";
const int projid = 0x77;

class Shm
{
private:
    void Create(int flg)
    {
        _shmid = shmget(_key, _size, flg);
        if(_shmid < 0)
        {
            ERR_EXIT("shmget");
            return;
        }
        printf("The _shmid is %d\n", _shmid);
    }

    void* Attach()
    {
        _start_mem = shmat(_shmid, nullptr, 0);
        printf("Virtual Address is %p\n", _start_mem);
        printf("attach sucess!\n");
        return _start_mem;
    }

    void Detach()
    {
        int n = shmdt(_start_mem);
        if(n == 0)
        {
            std::cout << "successfully detach" << _shmid << std::endl;
        }
    }

    void Destroy()
    {
        int n = shmctl(_shmid, IPC_RMID, nullptr);
        if(n < 0)
        {
            ERR_EXIT("shmctl");
            return;
        }
        else
        {
            printf("successfully remove %d", _shmid);
        }
    }
public:
    Shm(const std::string& usertype) 
    : _shmid(GDEFAULTNUM)
    , _size(GSIZE)
    , _start_mem(nullptr)
    , _usertype(usertype)
    {
        _key = ftok(pathname.c_str(), projid);
        if(_key < 0)
        {
            ERR_EXIT("ftok");
            return;
        }
        printf("Have gotten a key:0x%x\n", _key);
        if(_usertype == CREATER)
        {
            Create(IPC_CREAT|IPC_EXCL|0666);
        }
        else
        {
            Create(IPC_CREAT);
        }
        Attach();
    }

    ~Shm()
    {
        Detach();
        if(_usertype == CREATER)
        {
            Destroy();
        }
    }
private:
    int _shmid;
    int _size;
    key_t _key;
    void* _start_mem;
    std::string _usertype;
};